package com.selune.online.ordering.system.project.customer.service;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.selune.online.ordering.system.common.component.WebSocketComponent;
import static com.selune.online.ordering.system.common.util.IdUtils.orderGenId;
import com.selune.online.ordering.system.project.api.base.constant.enums.OrderStatusEnum;
import com.selune.online.ordering.system.project.api.base.constant.enums.PayStatusEnum;
import com.selune.online.ordering.system.project.api.base.entity.CustomerUserInfo;
import com.selune.online.ordering.system.project.api.base.entity.OrderDetail;
import com.selune.online.ordering.system.project.api.base.entity.OrderOverview;
import com.selune.online.ordering.system.project.api.base.exception.OrderException;
import com.selune.online.ordering.system.project.api.base.response.Response;
import com.selune.online.ordering.system.project.api.mapper.CustomerUserInfoMapper;
import com.selune.online.ordering.system.project.api.mapper.GoodsInfoMapper;
import com.selune.online.ordering.system.project.api.mapper.OrderDetailMapper;
import com.selune.online.ordering.system.project.api.mapper.OrderOverviewMapper;
import com.selune.online.ordering.system.project.api.pojo.order.dto.CartGoodsDTO;
import com.selune.online.ordering.system.project.api.pojo.order.dto.OrderDTO;
import com.selune.online.ordering.system.project.api.pojo.order.vo.OrderOverviewVO;
import com.selune.online.ordering.system.project.api.pojo.order.vo.OrderVO;
import com.selune.online.ordering.system.project.api.service.customer.ICustomerOrderService;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * Created with IntelliJ IDEA.
 *
 * @author xiaoyp
 * @date 2020/3/24
 * <p>
 * Description:
 */
@Service
@Slf4j
public class CustomerOrderServiceImpl implements ICustomerOrderService {
	
	@Resource
	private OrderOverviewMapper orderOverviewMapper;
	@Resource
	private OrderDetailMapper orderDetailMapper;
	@Resource
	private GoodsInfoMapper goodsInfoMapper;
	@Resource
	private CustomerUserInfoMapper customerUserInfoMapper;
	
	@Autowired
	private WebSocketComponent webSocket;
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Response<OrderVO> saveOrder(OrderDTO orderDTO) {
		
		if (null == orderDTO || CollectionUtils.isEmpty(orderDTO.getGoodsDTOList())) {
			log.error("ACCESS_LOG[]CustomerOrderServiceImpl[]saveOrder[]cart is null");
			throw new OrderException("购物车为空");
		}
		
		Long userId = orderDTO.getUserId();
		CustomerUserInfo customerUserInfo = customerUserInfoMapper.selectById(userId);
		if (ObjectUtils.isEmpty(customerUserInfo)) {
			log.error("ACCESS_LOG[]CustomerOrderServiceImpl[]saveOrder[]user is not exist");
			throw new OrderException("用户不存在");
		}
		
		OrderOverview orderOverview = new OrderOverview();
		List<OrderDetail> orderDetailList = new ArrayList<>(orderDTO.getGoodsDTOList().size());
		
		cartToOrder(orderDTO, orderOverview, orderDetailList);
		
		AtomicInteger goodsResult = new AtomicInteger(0);
		int overviewResult = orderOverviewMapper.insert(orderOverview);
		orderDetailList.forEach(orderDetail -> {
			orderDetailMapper.insert(orderDetail);
			goodsResult.getAndIncrement();
		});
		
		List<CartGoodsDTO> cartGoodsDTOList = new ArrayList<>(orderDetailList.size());
		orderDetailList.forEach(orderDetail -> {
			CartGoodsDTO cartGoodsDTO = new CartGoodsDTO();
			cartGoodsDTO.setGoodsId(orderDetail.getGoodsId());
			cartGoodsDTO.setGoodsName(orderDetail.getGoodsName());
			cartGoodsDTO.setGoodsPrice(orderDetail.getGoodsPrice());
			cartGoodsDTO.setGoodsQuantity(orderDetail.getGoodsQuantity());
			cartGoodsDTO.setGoodsPicture(orderDetail.getGoodsPicture());
			cartGoodsDTOList.add(cartGoodsDTO);
		});
		
		OrderVO orderVO = new OrderVO();
		orderVO.setOrderId(orderOverview.getOrderId());
		orderVO.setOrderPersonName(orderOverview.getOrderPersonName());
		orderVO.setOrderPersonPhone(orderOverview.getOrderPersonPhone());
		orderVO.setOrderAmount(orderOverview.getOrderAmount());
		orderVO.setOrderRemark(orderOverview.getOrderRemark());
		orderVO.setGoodsDTOList(cartGoodsDTOList);
		
		if (overviewResult == 1 && goodsResult.get() == orderDTO.getGoodsDTOList().size()) {
			return Response.success("订单创建成功!", orderVO);
		} else {
			return Response.error("订单创建失败");
		}
	}
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Response<Boolean> payOrder(Long orderId) {
		if (null == orderId) {
			log.error("ACCESS_LOG[]CustomerOrderServiceImpl[]payOrder[]order id is null");
			throw new OrderException("订单id为空");
		}
		
		List<OrderDetail> orderDetailList = orderDetailMapper.selectList(
			Wrappers.<OrderDetail>lambdaQuery().eq(OrderDetail::getOrderId, orderId)
		);
		// 扣库存
		orderDetailList.forEach(cartGoodsDTO -> {
			Long goodsId = cartGoodsDTO.getGoodsId();
			Long quantity = cartGoodsDTO.getGoodsQuantity();
			Long stock = goodsInfoMapper.selectById(goodsId).getGoodsStock();
			if (quantity > stock) {
				throw new OrderException("库存不足!");
			}
			goodsInfoMapper.decreaseStock(goodsId, quantity);
		});
		
		int result = orderOverviewMapper.update(
			null,
			Wrappers.<OrderOverview>lambdaUpdate()
				.eq(OrderOverview::getOrderId, orderId)
				.set(OrderOverview::getPayStatus, PayStatusEnum.PAID.code())
				.set(OrderOverview::getPayTime, new Date())
		);
		
		if (result != 1) {
			throw new OrderException("支付失败");
		}
		
		webSocket.sendMessage("新订单：" + orderId);
		
		// TODO 调用支付接口,支付失败回滚
		
		return Response.success("支付成功!", Boolean.TRUE);
	}
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Response<Boolean> cancelOrder(Long orderId) {
		if (null == orderId) {
			log.error("ACCESS_LOG[]CustomerOrderServiceImpl[]cancelOrder[]order id is null");
			throw new OrderException("订单id为空");
		}
		
		List<OrderDetail> orderDetailList = orderDetailMapper.selectList(
			Wrappers.<OrderDetail>lambdaQuery().eq(OrderDetail::getOrderId, orderId)
		);
		
		// 加库存
		orderDetailList.forEach(cartGoodsDTO -> {
			Long goodsId = cartGoodsDTO.getGoodsId();
			Long quantity = cartGoodsDTO.getGoodsQuantity();
			goodsInfoMapper.increaseStock(goodsId, quantity);
		});
		
		int result = orderOverviewMapper.update(
			null,
			Wrappers.<OrderOverview>lambdaUpdate()
				.eq(OrderOverview::getOrderId, orderId)
				.set(OrderOverview::getPayStatus, PayStatusEnum.REFUNDED.code())
				.set(OrderOverview::getCancelTime, new Date())
		);
		
		if (result != 1) {
			throw new OrderException("订单取消失败");
		}
		
		// TODO 调用退款接口,退款失败回滚
		
		return Response.success("订单取消成功!", Boolean.TRUE);
	}
	
	@Override
	public Response<List<OrderOverviewVO>> listOrder(Long userId) {
		if (null == userId) {
			log.error("ACCESS_LOG[]CustomerOrderServiceImpl[]listOrder[]user id is null");
			throw new OrderException("用户id为空");
		}
		
		List<OrderOverview> orderOverviewList = orderOverviewMapper.selectList(
			Wrappers.<OrderOverview>lambdaQuery().eq(OrderOverview::getUserId, userId)
				.orderByDesc(OrderOverview::getUpdateTime)
		);
		
		List<OrderOverviewVO> orderOverviewVOList = new ArrayList<>(orderOverviewList.size());
		
		orderToVO(orderOverviewList, orderOverviewVOList);
		
		return Response.success(orderOverviewVOList);
	}
	
	@Override
	public Response<OrderVO> getOrderById(Long orderId) {
		if (null == orderId) {
			log.error("ACCESS_LOG[]CustomerOrderServiceImpl[]listOrder[]order id is null");
			throw new OrderException("订单id为空");
		}
		OrderOverview orderOverview = orderOverviewMapper.selectById(orderId);
		if (ObjectUtils.isEmpty(orderOverview)) {
			log.error("ACCESS_LOG[]CustomerOrderServiceImpl[]listOrder[]order is exist");
			throw new OrderException("订单不存在");
		}
		
		List<OrderDetail> orderDetailList = orderDetailMapper.selectList(
			Wrappers.<OrderDetail>lambdaQuery().eq(OrderDetail::getOrderId, orderId));
		
		List<CartGoodsDTO> cartGoodsDTOList = new ArrayList<>(orderDetailList.size());
		orderDetailList.forEach(orderDetail -> {
			CartGoodsDTO cartGoodsDTO = new CartGoodsDTO();
			cartGoodsDTO.setGoodsId(orderDetail.getGoodsId());
			cartGoodsDTO.setGoodsName(orderDetail.getGoodsName());
			cartGoodsDTO.setGoodsPicture(orderDetail.getGoodsPicture());
			cartGoodsDTO.setGoodsQuantity(orderDetail.getGoodsQuantity());
			cartGoodsDTO.setGoodsPrice(orderDetail.getGoodsPrice());
			cartGoodsDTOList.add(cartGoodsDTO);
		});
		
		OrderVO orderVO = new OrderVO();
		orderVO.setOrderId(orderOverview.getOrderId());
		orderVO.setUserId(orderOverview.getUserId());
		orderVO.setOrderPersonName(orderOverview.getOrderPersonName());
		orderVO.setOrderPersonPhone(orderOverview.getOrderPersonPhone());
		orderVO.setOrderAddress(orderOverview.getOrderAddress());
		orderVO.setOrderAmount(orderOverview.getOrderAmount());
		orderVO.setOrderRemark(orderOverview.getOrderRemark());
		orderVO.setGoodsDTOList(cartGoodsDTOList);
		
		return Response.success(orderVO);
	}
	
	private void cartToOrder(OrderDTO orderDTO,
	                         OrderOverview orderOverview,
	                         List<OrderDetail> orderDetailList) {
		Long orderId = orderGenId();
		
		List<CartGoodsDTO> cartGoodsDTOList = orderDTO.getGoodsDTOList();
		
		// 订单总览
		orderOverview.setId(orderId);
		orderOverview.setOrderId(orderId);
		orderOverview.setUserId(orderDTO.getUserId());
		orderOverview.setOrderPersonName(orderDTO.getOrderPersonName());
		orderOverview.setOrderPersonPhone(orderDTO.getOrderPersonPhone());
		orderOverview.setOrderAddress(orderDTO.getOrderAddress());
		orderOverview.setOrderAmount(orderDTO.getOrderAmount());
		orderOverview.setOrderRemark(orderDTO.getOrderRemark());
		orderOverview.setOrderStatus(OrderStatusEnum.NEW_ORDER.code());
		orderOverview.setPayStatus(PayStatusEnum.UNPAID.code());
		
		// 订单详情
		cartGoodsDTOList.forEach(cartGoodsDTO -> {
			OrderDetail orderDetail = new OrderDetail();
			orderDetail.setOrderId(orderId);
			orderDetail.setGoodsId(cartGoodsDTO.getGoodsId());
			orderDetail.setGoodsName(cartGoodsDTO.getGoodsName());
			orderDetail.setGoodsPrice(cartGoodsDTO.getGoodsPrice());
			orderDetail.setGoodsQuantity(cartGoodsDTO.getGoodsQuantity());
			orderDetail.setGoodsPicture(cartGoodsDTO.getGoodsPicture());
			
			orderDetailList.add(orderDetail);
		});
	}
	
	private void orderToVO(List<OrderOverview> orderOverviewList, List<OrderOverviewVO> orderOverviewVOList) {
		
		for (OrderOverview orderOverview : orderOverviewList) {
			Long orderId = orderOverview.getOrderId();
			List<OrderDetail> orderDetailList = orderDetailMapper.selectList(
				Wrappers.<OrderDetail>lambdaQuery().eq(OrderDetail::getOrderId, orderId));
			OrderOverviewVO orderOverviewVO = new OrderOverviewVO();
			orderOverviewVO.setOrderId(orderId);
			orderOverviewVO.setOrderPersonName(orderOverview.getOrderPersonName());
			orderOverviewVO.setOrderPersonPhone(orderOverview.getOrderPersonPhone());
			orderOverviewVO.setOrderAddress(orderOverview.getOrderAddress());
			orderOverviewVO.setOrderAmount(orderOverview.getOrderAmount());
			orderOverviewVO.setOrderRemark(orderOverview.getOrderRemark());
			orderOverviewVO.setOrderStatus(orderOverview.getOrderStatus());
			
			// 时间填充
			if (orderOverview.getPayStatus() == 1) {
				orderOverviewVO.setTime(orderOverview.getPayTime());
			} else {
				if (orderOverview.getOrderStatus() == 0) {
					orderOverviewVO.setTime(orderOverview.getCreateTime());
				} else if (orderOverview.getOrderStatus() == 1) {
					orderOverviewVO.setTime(orderOverview.getFinishTime());
				} else if (orderOverview.getOrderStatus() == 2) {
					orderOverviewVO.setTime(orderOverview.getCancelTime());
				} else {
					orderOverviewVO.setTime(orderOverview.getUpdateTime());
				}
			}
			
			List<CartGoodsDTO> goodsList = new ArrayList<>(orderDetailList.size());
			orderDetailList.forEach(orderDetail -> {
				CartGoodsDTO cartGoodsDTO = new CartGoodsDTO();
				cartGoodsDTO.setGoodsId(orderDetail.getGoodsId());
				cartGoodsDTO.setGoodsName(orderDetail.getGoodsName());
				cartGoodsDTO.setGoodsPrice(orderDetail.getGoodsPrice());
				cartGoodsDTO.setGoodsQuantity(orderDetail.getGoodsQuantity());
				cartGoodsDTO.setGoodsPicture(orderDetail.getGoodsPicture());
				goodsList.add(cartGoodsDTO);
			});
			orderOverviewVO.setGoodsList(goodsList);
			
			orderOverviewVOList.add(orderOverviewVO);
		}
	}
}
